from PyQt5.QtGui import QKeyEvent,QIntValidator
from PyQt5.QtWidgets import  QApplication,QMainWindow,QFileDialog,QAbstractItemView
from PyQt5.QtCore import QTimer,Qt,pyqtSignal,QCoreApplication,QFile
import Ui_main as u1

#==功能性包
import numpy as np
import soundfile as sf
import sounddevice as sd
from utils import trans
from asmr import virtual_surround

class MainView(QMainWindow):
    def __init__(self):
        super().__init__()
        self.ui =u1.Ui_MainWindow()
        self.ui.setupUi(self)
        #==================初始化==================
        self.ui.ori_list.setSelectionMode(QAbstractItemView.MultiSelection)
        self.grabKeyboard
        self.ui.blank_fps.setValidator(QIntValidator(0, 1000000))

        #==================变量==================
        self.ori_data = [] # 存音频对象(下标与列表中的位置序号对应)
        self.pos_data = [] # 存放环绕位置信息（h,v）

        self.res_data = [] # 处理结果
        self.ori_multi_select=False

        #==================信号与槽==================
        self.ui.load_action.triggered.connect(self.load_audio)
        self.ui.ori_list.currentRowChanged.connect(self._show_info)
        #self.ui.ori_list.itemChanged.connect(lambda a:print("item changed"))
        #self.ui.ori_list.itemEntered.connect(lambda:print("item enter"))
        self.ui.ori_list.exchange_signal.connect(self.exchange_item)
        self.ui.play_bnt.clicked.connect(self.play_audio)
        self.ui.save_bnt.clicked.connect(self.save_result)
        self.ui.clear_res_bnt.clicked.connect(self.clear_res)

        self.ui.add_pos.clicked.connect(self.append_pos)
        self.ui.del_pos.clicked.connect(self.delete_pos)
        self.ui.virtual_surround_bnt.clicked.connect(self.virtual_surround)

        
        self.ui.format_convert_bnt.clicked.connect(self.format_convert)
        self.ui.audio_merge_bnt.clicked.connect(self.audio_merge)
    
    def clear_res(self):
        """清空结果列表"""
        print("清空结果列表")
        self.ui.res_list.clear()
        self.res_data.clear()

    def virtual_surround(self):
        """虚拟环绕"""
        sel_items = self.ui.ori_list.selectedItems()
        if len(sel_items)<1:
            print("未选中音频")
            return
        # 获取音频数据
        data =self.ori_data[self.ui.ori_list.row(sel_items[0])]["data"]
        samplerate = self.ori_data[self.ui.ori_list.row(sel_items[0])]["samplerate"]
        slice_size = int(self.ui.slice_size.text())

        res = virtual_surround(sound_path="",source_voice=data,samplerate=samplerate,slice_size=slice_size,conv_list=self.pos_data)
        self.ui.res_list.addItem("result.wav")
        self.res_data.append({
            "data":res,
            "samplerate":samplerate,
            "name":"result.wav"
        })

    def delete_pos(self):
        """删除环绕位置"""
        print("删除环绕位置")
        sel_items = self.ui.conv_list.selectedItems()
        if len(sel_items)<1:
            print("未选中环绕位置")
            return
        index = self.ui.conv_list.row(sel_items[0])
        self.ui.conv_list.takeItem(index) # 自动垃圾回收
        self.pos_data.pop(index)
        print(self.pos_data)

    def append_pos(self):
        """添加环绕位置"""
        h = self.ui.h_angle.value()
        v = self.ui.v_angle.value()
        self.ui.conv_list.addItem(f"({h},{v})")
        self.pos_data.append((h,v))
        print(self.pos_data)

    def save_result(self):
        """保存结果"""
        print("保存结果")
        sd.stop()
        # 获取选中的音频序号
        sel_items = self.ui.res_list.selectedItems()
        if len(sel_items)<1:
            print("未选中音频")
            return
        # 获取音频数据
        data =self.res_data[self.ui.res_list.row(sel_items[0])]["data"]
        samplerate = self.res_data[self.ui.res_list.row(sel_items[0])]["samplerate"]
        output_path = self._saveFile()
        if output_path:
            sf.write(output_path, data, samplerate,format='WAV')
            return
 

    def play_audio(self):
        """播放结果列表中所选的音频"""
        print("播放音频")

        # 只有一个结果，直接播放
        if self.ui.res_list.count()==1:
            data =self.res_data[0]["data"]
            samplerate = self.res_data[0]["samplerate"]
            sd.play(data,samplerate)
            return
        # 获取选中的音频序号
        sel_items = self.ui.res_list.selectedItems()
        if len(sel_items)<1:
            print("未选中音频")
            return
        # 获取音频数据
        data =self.res_data[self.ui.res_list.row(sel_items[0])]["data"]
        samplerate = self.res_data[self.ui.res_list.row(sel_items[0])]["samplerate"]
        sd.play(data,samplerate)
        
        
     
    def exchange_item(self,a:int,b:int):
        """交换音频文件在列表中的位置（内存中的数据位置也对应改变）"""
        print("移动前：{},移动后{}".format(a,b))
        #print(str([i["name"] for i in self.ori_data]))
        # 将ori_data中的数据进行移动
        self.ori_data.insert(b,self.ori_data.pop(a))
        
        #print(str([i["name"] for i in self.ori_data]))

    def keyPressEvent(self, event: QKeyEvent) -> None:
        # 如果按下ctrl键
        if event.key() == Qt.Key_Control:
            self.ori_multi_select = True
    
    def keyReleaseEvent(self, event: QKeyEvent) -> None:
        # 如果松开ctrl键
        if event.key() == Qt.Key_Control:
            self.ori_multi_select = False
        
    def _saveFile(self):
        #self指向自身，"Open File"为文件名，"./"为当前路径，最后为文件类型筛选器
        fname,ftype = QFileDialog.getSaveFileName(self, "Save File", "./", "All Files(*);;Wav(*.wav)")
        return fname

    def audio_merge(self):
        """音频合并"""
        print("音频合并")
        # 获取选中的音频序号
        sel_items = self.ui.ori_list.selectedItems()
        if len(sel_items)<2:
            print("未选中音频或者选中音频少于2个")
            return
        sel_index = [self.ui.ori_list.row(item) for item in sel_items] 
        # 排序
        sel_index.sort()
        print(sel_index)


        blank_fps=int(self.ui.blank_fps.text()) # 空白帧数
        
        data = []
        # 提取音频数据
        for index in sel_index:
            data.append(self.ori_data[index]["data"])
            data.append(np.zeros((blank_fps, )))

        # 拼接音频数据
        data = np.concatenate(data, axis=0)

        # # 保存音频文件
        # output_path = self._saveFile()
        # if output_path:
        #     sf.write(output_path, data, self.ori_data[sel_index[0]]["samplerate"],format='WAV')
        #     return
        # print("操作取消")

        # 暂存音频文件
        self.ui.res_list.addItem("result.wav")
        self.res_data.append({
            "data":data,
            "samplerate":self.ori_data[sel_index[0]]["samplerate"],
            "name":"result.wav"
        })
        
  

    def format_convert(self):
        """格式转换"""
        print("格式转换")
        pass
        

    def _readDir(self):
        #self指向自身，"Open File"为文件名，"./"为当前路径，最后为文件类型筛选器
        directory1 = QFileDialog.getExistingDirectory(self,"选取文件夹","./")
        return directory1

    def _readFile(self):
        #self指向自身，"Open File"为文件名，"./"为当前路径，最后为文件类型筛选器
        fname,ftype = QFileDialog.getOpenFileName(self, "Open File", "./", "All Files(*);;Wav(*.wav)")#如果添加一个内容则需要加两个分号
        # 该方法返回一个tuple,里面有两个内容，第一个是路径， 第二个是要打开文件的类型，所以用两个变量去接受
        # 如果用户主动关闭文件对话框，则返回值为空
        return fname
        
    def _show_info(self,index:int):
        """显示选中音频信息；当顺序改变时，同步调整ori_adta的顺序"""
        print(f"选中行数：{index}\n信号触发")
        if index<0:
            return
        if not self.ori_multi_select: # 如果没有不处于多选模式（没有按住ctrl键）
            self.ui.ori_list.clearSelection()
            
        print("显示音频信息")
        self.ui.sample_rate.setText(str(self.ori_data[index]["samplerate"]))
        self.ui.fps_num.setText(str(self.ori_data[index]["data"].shape[0]))
        self.ui.channel_num.setText(str(self.ori_data[index]["data"].ndim))
        self.ui.name.setText(self.ori_data[index]["name"])

    def _show_audio(self,name:str):
        """显示音频文件到列表中"""

        # TODO: 如果存在同名文件，需要重命名

        self.ui.ori_list.addItem(name)
        self.ui.ori_list.setCurrentRow(self.ui.ori_list.count()-1)
        self.ui.ori_list.clearSelection()
        self.ui.ori_list.item(self.ui.ori_list.count()-1).setSelected(True)
     
    def load_audio(self):
        """加载音频文件"""
        print("加载音频文件")
        fname = self._readFile()
        if fname:
            data, samplerate = sf.read(fname)
          
            name = fname.split("/")[-1]
            # 如果存在同名文件，需要重命名
            for i in range(len(self.ori_data)):
                if self.ori_data[i]["name"]==name:
                    name = name.split(".")[0]+"_"+str(i)+"."+name.split(".")[-1]
                    break
            # 构建音频对象
            sd_obj={
                "data":data,
                "samplerate":samplerate,
                "name":name,
                "path":fname
            }
            # 添加到列表中
            self.ori_data.append(sd_obj)
           
            self._show_audio(name)
            print("加载成功")
        else:
            print("加载失败")
        
        

if __name__=="__main__":
    import sys

    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)

    app = QApplication(sys.argv)


    main = MainView()
    main.show()
    sys.exit(app.exec_())